home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / VOXEL.ZIP / VOXEL.C < prev   
Encoding:
C/C++ Source or Header  |  1995-09-03  |  14.2 KB  |  508 lines

  1. // voxel demo
  2. //
  3. // 95-03-Sep.
  4. // jeff bilger
  5. // eusjeb@exu.ericsson.se
  6. // (Send me email if you have any comments)
  7. //
  8. // *********************
  9. // * Overview          *
  10. // *********************
  11. // This program will 
  12. //      generate a voxel terrain map and place this data in a 2d array
  13. //      rotate the terrain map data about x,y,z
  14. //      sort the voxel terrain map data by z (small values)
  15. //      finally display the voxel map to the crt.
  16. //      A virtual window can be defined, see the #define section
  17. //
  18. // *********************
  19. // * History           *
  20. // *********************
  21. // uses quick sort
  22. // added a period, and a granularity input, 
  23. // the gen_map fnct uses these vars to compute the voxel map
  24. //   - added rotations about all 3 axes.
  25. //   - removed temp[][] array. No need to copy WIDTH*HEIGHT*3 words
  26. //     per display anymore. 
  27. //   - added angle incr settings
  28. //   - color is indep. of height once transformations occur. 
  29. //     the color is only dependent on the *original* heght now
  30. //   - added logic to clip at the crt window
  31. //   - optimized for speed (rotate/display) 
  32. //
  33. //
  34. //
  35.  
  36. #include <dos.h>
  37. #include <math.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <conio.h>
  41. #include "..\library\grafix.h"
  42.  
  43.  
  44. /**********************/
  45. /* Function Prototypes*/
  46. /**********************************************************************/
  47. void main();
  48. void init();
  49. void build_palette();
  50. void display_();
  51. void draw_voxel(int,int,int,int);
  52. void gen_map();
  53. void rotate(double);
  54. void _qsort(int,int);
  55. void swap(int,int);
  56.  
  57.  
  58. /*********/
  59. /*Defines*/
  60. /**********************************************************************/
  61.  
  62. #define DEPTH 20                  // depth of the terrain map (z)
  63. #define WIDTH 40                  // width of the terrain map (x)
  64. #define X_ORIGIN 100              // x,y origin of the screen
  65. #define Y_ORIGIN 100
  66. #define MAX_HEIGHT 50.0           // max height of the terrain
  67. #define INITIAL_HEIGHT 5          // initial height of the terrain
  68. #define PI      3.1415
  69. #define NO  0 
  70. #define YES 1
  71. #define XW_MIN 10                // coords that define the 'virtual'
  72. #define XW_MAX 300               // window on the crt
  73. #define YW_MIN 5
  74. #define YW_MAX 190
  75.  
  76.  
  77. /***************/
  78. /* Structures  */
  79. /********************************************************************/
  80.  
  81. struct pts                        // structure for terrain map data
  82. {
  83.  float x,y,z,color;
  84. };
  85. typedef struct pts TERRAIN_POINTS;
  86.  
  87. struct pts_int                    // structure for display map data
  88. {
  89. int x,y,z,color;
  90. };
  91. typedef struct pts_int DISPLAY_POINTS;
  92.  
  93.  
  94. TERRAIN_POINTS map[DEPTH][WIDTH];        // holds original terrain coords
  95. DISPLAY_POINTS display[DEPTH*WIDTH];     // holds  coords to display on the
  96.                                          // crt after transformations and 
  97.                                          // sorting
  98.  
  99.  
  100.  
  101. /***********/
  102. /* Globals */
  103. /*****************************************************************/
  104.  
  105. char far      *SCR;             // ptrs to video memory
  106. char          *BACK;            // and our double buffer
  107. unsigned char PAL[256*3];       // 256 colors (rgb) for the palette 
  108. float         PERIOD,           // user defined period  
  109.               COS_10,           // for roataions 
  110.               SIN_10;
  111. int           GRANULARITY,      // user defined size of voxel
  112.               THETA_INCR;       // user defined angle increment for rotations
  113. char          CLIPPING = NO;    // clipping flag
  114.  
  115.  
  116.  
  117.  
  118. /**************/
  119. /* Main()     */
  120. /********************************************************************/
  121.  
  122. void main()
  123. {                               
  124. double theta;                   // holds current angle
  125. int i=0;                        // counter 
  126.  
  127.  
  128. /***************************/
  129. /* Get user defined params.*/
  130. /***************************/
  131. printf("-Voxel landscape demo by Jeff Bilger (eusjeb@exu.ericsson.se)-\n");
  132. printf("Enter the period: (90,180,360 etc) (530 is a good value):");
  133. scanf("%f",&PERIOD);
  134. printf("Enter the length of the voxel sides: (1,2,3 etc) (2 is a good value):");
  135. scanf("%d",&GRANULARITY);
  136. printf("Enter the degree increment per rotation: (8 is a good value):");
  137. scanf("%d",&THETA_INCR);
  138.  
  139.  
  140.  
  141. /*******************************/
  142. /* Do some initialization stuff*/
  143. /*******************************/
  144. init();
  145.  
  146.  
  147. /****************/
  148. /* Main routine */
  149. /****************/
  150. while (!kbhit())                   // loop until user hits a key
  151. {
  152.  for(i=1;i<360;i+=THETA_INCR)      // For each iteration... 
  153.  {
  154.   theta = (double)i * PI / 180.0;  // convert current angle to radians
  155.  
  156.   rotate(theta);                   // rotate map and save to 1d display array
  157.   _qsort(0,DEPTH*WIDTH-1);         // sort it
  158.   display_();                      // save it to double buffer
  159.   G_WaitRetrace();
  160.   G_memcpy_word(SCR,BACK,320*200/2); // display it to the crt
  161.   G_Set_screen_color(0,BACK);      // erase the double buffer and repeat..
  162.  }
  163.  
  164. theta = 0.0;                       // if a full 360 degree revolution has 
  165.                                    // finished, reset the angle and repeat...
  166. }
  167. G_Text_mode();                     // Go back to text mode
  168.  
  169. }                                  // end of main()
  170.  
  171. /*******************************************************************/
  172. /*******************************************************************/
  173.  
  174.  
  175.  
  176.  
  177.  
  178. /************************/
  179. /* Procedures/Functions */
  180. /*******************************************************************/
  181.  
  182. // [%]===========================[%]
  183. // [%]build palette              [%]
  184. // [%]===========================[%]
  185. //
  186. // This procedure will generate the palette that will be used
  187. // to display the voxel terrain.
  188. //
  189. // In video mode 13h, the PC can display 256 colors from the palette
  190. // The palette has 256 entries and each entry is defined by a RGB color 
  191. // value. The RGB value is 18 bits long thus 6 bits are used  
  192. // for the R component, 6 bits for the G comp. and 6 bits for the B comp. 
  193. // Thus each component can have a max value of 64 (2^6 = 64)
  194. //
  195. // The palette will be built such that whites/light greens are in the
  196. // lower color entries and dark greens are in the higher entries
  197. void build_palette()
  198. {
  199. int i;
  200. int r=63,g=63,b=63;          // for palette setting
  201.  
  202. PAL[0]= 0;                  // 1st pal entry is the background, we cant that
  203. PAL[1]=0;                   // to be BLACK (rgb = 0,0,0)
  204. PAL[2]=0;
  205.  
  206.  
  207. for(i=3;i<52*3;i+=3)        // set next 52 color entries
  208.  {
  209.   PAL[i] = r;
  210.   PAL[i+1] = g;
  211.   PAL[i+2] = b;
  212.   if(i%9==0) { r--;g--;b--;}
  213.  }
  214.  
  215.  
  216.  g=63;
  217. for(;i<256*3;i+=3)         // set the rest of the color entries
  218.  {
  219.   PAL[i] = 0;
  220.   PAL[i+1] = g--;
  221.   PAL[i+2] = 0;
  222.  }
  223.  
  224. }
  225.  
  226.  
  227.  
  228.  
  229. // [%]===========================[%]
  230. // [%]init                       [%]
  231. // [%]===========================[%]
  232. //
  233. // Just set up some stuff
  234. void init()
  235. {
  236. SCR = (char far *) MK_FP(0xa000,0);       // setup addr to video memory
  237. BACK =(char *) malloc(64000);             // alloc memory for double buffer
  238. if(BACK == NULL) exit(0);
  239.  
  240.  COS_10 = cos(10.0*PI/180.0);             // for use in rotations
  241.  SIN_10 = sin(10.0*PI/180.0);
  242.  
  243. G_Int13_mode();             // enter video mode 13h
  244. build_palette();            // build the palette
  245. G_SetPal(PAL,0,256);        // assign the new palette
  246. gen_map();                  // build terrain map
  247.  
  248. }
  249.  
  250.  
  251.  
  252.  
  253.  
  254. // [%]===========================[%]
  255. // [%]display                    [%]
  256. // [%]===========================[%]
  257. // 
  258. // This procedure will draw the voxel landscape.
  259. // The array 'display[]'  contains the *sorted* voxel landscape 
  260. // data, it is sorted by z such that small z values occur first. Thus
  261. // we will draw from 'display[DEPTH * width  - 1] to [0]' or back to front
  262. void display_()
  263. {
  264.  int i,x1,y1,x2; 
  265.  
  266.  for(i=DEPTH*WIDTH -1 ;i>=0;i--)
  267.  {
  268.      x1 = display[i].x-GRANULARITY;     // define the length of the voxel 
  269.      y1 = display[i].y-GRANULARITY;
  270.      x2 = display[i].x+GRANULARITY;
  271.  
  272.                                         // see if any clipping needs to be 
  273.                                         // done
  274.      if (x1 < XW_MIN || x2 > XW_MAX || y1 < YW_MIN || y1+10 > YW_MAX)
  275.         CLIPPING = YES;
  276.     
  277.   
  278.   draw_voxel(x1,y1,x2, display[i].color);
  279.  
  280.  }
  281. }
  282.  
  283.  
  284.  
  285. // [%]===========================[%]
  286. // [%]draw_voxel                 [%]
  287. // [%]===========================[%]
  288. // 
  289. // draw the voxel
  290. void draw_voxel(int x1,int y1, int x2, int c)
  291. {
  292.   int x=x1;
  293.   int offset = y1*320; 
  294.   int loop;
  295.  
  296.   if ( !CLIPPING)
  297.   while(x++ <= x2)
  298.   {
  299.   *(BACK + (offset + x)) = c;           // all voxels will be 10 pixels
  300.   *(BACK + (offset + 320) + x) = c;     // high
  301.   *(BACK + (offset + 2*320) + x) = c;
  302.   *(BACK + (offset + 3*320) + x) = c;
  303.   *(BACK + (offset + 4*320) + x) = c;
  304.   *(BACK + (offset + 5*320) + x) = c;
  305.   *(BACK + (offset + 6*320) + x) = c;
  306.   *(BACK + (offset + 7*320) + x) = c;
  307.   *(BACK + (offset + 8*320) + x) = c;
  308.   *(BACK + (offset + 9*320) + x) = c;
  309.   }
  310.   
  311.   else  // CLIPPING is needed
  312.   {
  313.    loop = y1+10;               // each voxel is usually 10 pixels high
  314.  
  315.    if (x < XW_MIN) x=XW_MIN;               // case 1, 
  316.    else if (x2 > XW_MAX)  x2=XW_MAX;       // if case 1 is True, case 2
  317.                                            // can *never* be true unless you 
  318.                                            // defined GRANULARITY as some 
  319.                                            // value that is larger than 
  320.                                            // the width of your virtual window
  321.                                            // which would be stupid.
  322.  
  323.    if (y1 < YW_MIN)                   // case 3
  324.      {
  325.        loop = (10 + y1); 
  326.        y1 = YW_MIN;
  327.      }
  328.    else if ((y1 + 10) > YW_MAX)      // case 4 can never be true if case 3
  329.      loop = YW_MAX;                  // is true unless you define your 
  330.                                      // virtual window height as less than 10 
  331.                                      // (again, stupid..)
  332.    
  333.     for( ; y1<loop ; y1++)            // draw the clipped voxel  
  334.      while(x++ <= x2)
  335.      *(BACK + (y1*320 + x)) = c;
  336.    CLIPPING = NO;                     // turn clipping off
  337.   }
  338. }
  339.  
  340.  
  341.  
  342.  
  343.  
  344. // [%]===========================[%]
  345. // [%]gen_map                    [%]
  346. // [%]===========================[%]
  347. // 
  348. //
  349. // generates terrain using the sine function, this gives a 'hill-type'
  350. // effect
  351.  
  352. void gen_map()
  353. {
  354. int i=0,j=0,xincr=0,zincr=0;
  355. double height_incr = MAX_HEIGHT / ( (float)DEPTH / 2),
  356.        theta_incr  = PERIOD / (float)WIDTH,
  357.        height=INITIAL_HEIGHT,
  358.        theta=0;
  359.        int lastindex = DEPTH - 1; // point to last array index
  360.        int MAX_Z = GRANULARITY*DEPTH;
  361.  
  362. for (i=0;i<DEPTH/2;i++)   // generate it symmetrically (both back and front)
  363. {                         // at the same time.
  364.  for (j=0;j<WIDTH;j++)    
  365.   {                       // generate front side of the terrain
  366.     map[i][j].x = xincr+=GRANULARITY;  
  367.     map[i][j].z = zincr;
  368.     map[i][j].y = height * sin(theta * PI / 180.0);
  369.     map[i][j].color =Y_ORIGIN - map[i][j].y;   // set color the val of initial height
  370.  
  371.  
  372.  
  373.                          // generate back side of the terrain
  374.     map[lastindex-i][j].x = xincr+=GRANULARITY;
  375.     map[lastindex-i][j].z = MAX_Z;
  376.     map[lastindex-i][j].y = height * sin(theta * PI / 180.0);
  377.     map[lastindex-i][j].color = Y_ORIGIN - map[lastindex-i][j].y;   // set color the val of initial height
  378.  
  379.  
  380.  
  381.     theta += theta_incr;
  382.    
  383. //  printf("item[%d][%d] -- x =%f, z =%f , height=%f\n",i,j,map[i][j].x,map[i][j].z,map[i][j].y);
  384.   }
  385.   xincr=0;             // reset x increment
  386.   zincr+=GRANULARITY;  // increment front z
  387.   MAX_Z-=GRANULARITY;  // decrement back z
  388.  height += height_incr;  // incr. the height
  389.  theta =0;
  390. }
  391. }
  392.  
  393.  
  394.  
  395.  
  396.  
  397. // [%]===========================[%]
  398. // [%]rotate                     [%]
  399. // [%]===========================[%]
  400. // 
  401. // Rotate the voxel landscape
  402. //
  403. // theta is in radians
  404. // rotates about x,y,z
  405. // 
  406. void rotate(double theta)
  407. {
  408. int   i,j,k=0;
  409. float x,y,z;
  410. float tx,ty,tz;           // for temp storage of rotated points
  411. float cos_ = cos(theta),  // Rotation about y is the only roataion
  412.       sin_ = sin(theta);  // that depends on the current degree (in theta)
  413.                           // Rotation about x and z are always fixed at 10
  414.                           // degrees
  415.  
  416. for(i=0;i<DEPTH;i++)      // rotate for every voxel
  417.  for(j=0;j<WIDTH;j++)
  418.    {
  419.      /* rotate about y */
  420.      x = (float)map[i][j].x * cos_ + (float)map[i][j].z * sin_;
  421.      z = -(float)map[i][j].x * sin_ + (float)map[i][j].z * cos_;
  422.      tx = x;
  423.  
  424.      /* rotate about z */
  425.      x = tx * COS_10 - (float)map[i][j].y * SIN_10;
  426.      y = tx * SIN_10 + (float)map[i][j].y * COS_10;
  427.    
  428.      ty=y;
  429.      tz=z;
  430.  
  431.      /* rotate about x */
  432.      y = ty * COS_10 - tz * SIN_10;
  433.      z = ty * SIN_10 + tz * COS_10;
  434.  
  435. //   printf("theta:%f x:%f z:%f cos(%f)=%f\n",theta,x,z,theta,cos(theta));
  436.  
  437.      //save transformed coords into 1 d array
  438.      
  439.      display[k].x = x + X_ORIGIN;
  440.      display[k].y = Y_ORIGIN - y;  // flip the image
  441.      display[k].z = z + 50;
  442.      display[k].color = map[i][j].color; // save the color
  443.      k++;
  444.    }
  445.    
  446.    }
  447.  
  448.  
  449.  
  450.  
  451.  
  452. // [%]===========================[%]
  453. // [%]qsort                      [%]
  454. // [%]===========================[%]
  455. // sorts lowest z to highest z
  456. void _qsort(int l, int r)
  457. {
  458.  int j,k;
  459.  
  460.  if (l < r)
  461.   {
  462.     if(display[l].z > display[r].z)
  463.       swap(l,r);
  464.       j=l;k=r;
  465.       do
  466.       {
  467.        do{ j++; }while(display[j].z < display[l].z);
  468.        do{ k--; }while(display[k].z > display[l].z);
  469.        if  (j<k) swap(j,k);
  470.       }while(j<=k);
  471.      swap(l,k);
  472.     _qsort(l,k-1);
  473.     _qsort(k+1,r);
  474.   }
  475. }
  476.  
  477.  
  478. // [%]===========================[%]
  479. // [%]swap                       [%]
  480. // [%]===========================[%]
  481. //
  482. // used to swap points in the qsort function
  483. void swap(int l,int r)
  484.  {
  485.   DISPLAY_POINTS t;
  486.   
  487.  t.x = display[l].x;             // save point
  488.  t.y = display[l].y;
  489.  t.z = display[l].z;
  490.  t.color = display[l].color;
  491.  
  492.  display[l].x = display[r].x;     // do swap
  493.  display[l].y = display[r].y;
  494.  display[l].z = display[r].z;
  495.  display[l].color = display[r].color;
  496.  
  497.  display[r].x = t.x;            
  498.  display[r].y = t.y;
  499.  display[r].z = t.z;
  500.  display[r].color = t.color;
  501. }
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508.